package irpc

import (
	"gitee.com/tietang/terrace-go/v2/base"
	log "github.com/sirupsen/logrus"
	"github.com/tietang/props/v3/kvs"
	"net"
	"net/http"
	"net/rpc"
	"net/rpc/jsonrpc"
	"reflect"
	"sync"
)

func init() {
	//glog.SetFlags(glog.Ldate | glog.Ltime | glog.Lmicroseconds | glog.Lshortfile)

}

var once sync.Once

var Server *rpc.Server

func RpcServer() *rpc.Server {
	once.Do(func() {
		Server = rpc.NewServer()
	})
	return Server
}

func RpcRegister(rcvr interface{}) {
	typ := reflect.TypeOf(rcvr)
	log.Infof("goRPC Register: %s", typ.String())
	RpcServer().Register(rcvr)
}
func RpcRegisterName(name string, rcvr interface{}) {
	typ := reflect.TypeOf(rcvr)
	log.Infof("goRPC Register: %s= %s", name, typ.String())
	RpcServer().RegisterName(name, rcvr)
}

//Go RPC的函数只有符合下面的条件才能被远程访问，不然会被忽略，详细的要求如下：
//
//函数必须是导出的(首字母大写)
//必须有两个导出类型的参数，
//第一个参数是接收的参数，
//第二个参数是返回给客- 户端的参数，第二个参数必须是指针类型的
//第二个参数不允许在方法实现中重新被赋值，其字段可以赋值

//函数还要有一个返回值error
//
const (
	// Defaults used by HandleHTTP
	RPCPath   = "/_goRPC_"
	DebugPath = "/debug/rpc"
)

//初始化默认golang RPC 基于HTTP
func InitDefaultRPCForHTTP(conf kvs.ConfigSource) {
	//从配置文件中读取rpc端口
	port := conf.GetDefault("app.rpc.port", "8082")
	//注册http RPC 默认的上下文path和debug path
	rpc.HandleHTTP()
	//监听网络端口
	l, e := net.Listen("tcp", ":"+port)
	if e != nil {
		log.Fatal("listen error:", e)
	}
	log.Info("rpc default http port listened: ", port)
	go http.Serve(l, nil)
	//  默认方式
	//go http.ListenAndServe(":"+port, nil)
}

//初始化默认golang RPC
func InitRPCForTCP(conf kvs.ConfigSource) *rpc.Server {

	//从配置文件中读取rpc端口
	port := conf.GetDefault("app.rpc.port", "8082")
	//创建一个RPC 服务
	server := RpcServer()
	//监听网络端口
	listener, e := net.Listen("tcp", ":"+port)
	if e != nil {
		log.Fatal("listen error:", e)
	}
	log.Info("rpc tcp port listened: ", port)
	//处理网络连接和请求
	go server.Accept(listener)
	return server
}

//初始化默认golang json RPC
func InitJsonRPC(conf kvs.ConfigSource) *rpc.Server {
	port := conf.GetDefault("app.rpc.port", "8082")
	server := RpcServer()

	listener, e := net.Listen("tcp", ":"+port)
	if e != nil {
		log.Fatal("listen error:", e)
	}
	log.Info("jsonrpc TCP port listened: ", port)
	go func() {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err.Error())
		}
		// 绑定rpc的编码器，使用http connection新建一个jsonrpc编码器，并将该编码器绑定给http处理器
		go server.ServeCodec(jsonrpc.NewServerCodec(conn))
	}()
	return server
}

type GoRpcHttpStarter struct {
	base.BaseStarter
}

func (s *GoRpcHttpStarter) Start(ctx base.StarterContext) {
	InitDefaultRPCForHTTP(ctx.Props())
}

type JsonGoRpcTcpStarter struct {
	base.BaseStarter
}

func (s *JsonGoRpcTcpStarter) Start(ctx base.StarterContext) {
	InitJsonRPC(ctx.Props())
}

type GoRpcTcpStarter struct {
	base.BaseStarter
}

func (s *GoRpcTcpStarter) Start(ctx base.StarterContext) {
	InitRPCForTCP(ctx.Props())
}
func (s *GoRpcTcpStarter) Priority() int { return base.INT_MAX - 1 }
